package com.xiaochun.jiankangapp.base

import android.os.Bundle
import android.util.ArrayMap
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.viewbinding.ViewBinding
import com.xiaochun.jiankangapp.base.MvvmUtils.viewModel
import java.lang.reflect.Field

/**
 * 一些工具
 */
object MvvmUtils {

    /**
     * 反射形式查找ViewBinding
     */
    fun AppCompatActivity.findViewBindingAndSet(savedInstanceState: Bundle?) {
        val view = window.findViewById<ViewGroup>(android.R.id.content)
        val binding = findViewBinding(
            this,
            view,
            layoutInflater
        )
        binding?.root?.apply {
            if (view == this) {
                onContentChanged()
            } else {
                setContentView(this)
            }
        }
    }

    private val viewBindingField: ArrayMap<Class<Any?>, Field> = ArrayMap()

    /**
     * 反射形式调用 ViewBinding的inflate方法
     */
    @JvmStatic
    private fun viewBinding(
        container: ViewGroup? = null,
        layoutInflater: LayoutInflater, clazz: Class<ViewBinding?>
    ): ViewBinding {
        try {
            val method = clazz.getMethod(
                "inflate",
                LayoutInflater::class.java,
                ViewGroup::class.java,
                Boolean::class.java
            )
            method.isAccessible = true
            val result = method.invoke(null, layoutInflater, container, false)
            return result as ViewBinding
        } catch (e: NoSuchMethodException) {
            val method = clazz.getMethod(
                "inflate",
                LayoutInflater::class.java,
                ViewGroup::class.java
            )
            return method.invoke(null, layoutInflater, container) as ViewBinding
        }

    }

    /**
     * 反射形式查找ViewBinding
     */
    @Throws(exceptionClasses = [IllegalArgumentException::class])
    fun findViewBinding(
        finder: Any,
        viewGroup: ViewGroup?,
        layoutInflater: LayoutInflater
    ): ViewBinding? {
        val clazz = finder::class.java
        val field = viewBindingField[clazz]
        if (field != null) {
            return find(finder, field, viewGroup, layoutInflater)
        }
        try {
            val f = clazz.getDeclaredField("viewBinding")
            return find(finder, f, viewGroup, layoutInflater).apply {
                viewBindingField[clazz as Class<Any?>] = f
            }
        } catch (e: Exception) {
            e.printStackTrace()
            if (e is IllegalArgumentException) {
                throw e
            }
        }
        val fields = clazz.declaredFields
        fields.forEach { _f ->
            val a = _f.getAnnotation(CViewBinding::class.java)
            if (a != null) {
                return find(finder, _f, viewGroup, layoutInflater).apply {
                    viewBindingField[clazz as Class<Any?>] = _f
                }
            }
        }
        return null
    }

    @Throws(exceptionClasses = [IllegalArgumentException::class])
    private fun find(
        finder: Any,
        field: Field,
        viewGroup: ViewGroup?,
        layoutInflater: LayoutInflater
    ): ViewBinding {
        if (!ViewBinding::class.java.isAssignableFrom(field.type)) {
            throw IllegalArgumentException("Filed ${field.name} in Clazz ${finder::class.java.name} must be a sub class of ViewBinding")
        }
        field.isAccessible = true
        return viewBinding(
            viewGroup,
            layoutInflater,
            field.type as Class<ViewBinding?>
        ).apply {
            try {
                field.set(finder, this)
            } catch (e: Exception) {

            }
        }
    }

    /**
     * Fragment 和 Activity 可以使用此方法获取自己对应的Model
     * 获取一个ViewModel ，懒加载
     */
    inline fun <reified T : ViewModel> ViewModelStoreOwner.lazyViewModel(
        key: String? = null,
        factory: ViewModelProvider.Factory? = null
    ): Lazy<T> {
        return lazy(LazyThreadSafetyMode.NONE) {
            this.viewModel<T>(key, factory) as T
        }
    }

    /**
     *  非懒加载
     */
    inline fun <reified T : ViewModel> ViewModelStoreOwner.viewModel(
        key: String? = null,
        factory: ViewModelProvider.Factory? = null
    ): T {
        val provider =
            if (factory == null) ViewModelProvider(this) else ViewModelProvider(this, factory)
        return if (key != null) {
            provider[key, T::class.java]
        } else {
            provider[T::class.java]
        }
    }
}

/**
 * Fragment 和 Activity 可以使用此方法获取自己对应的Model
 * 获取一个ViewModel ，懒加载
 */
inline fun <reified T : ViewModel> lazyGlobalViewModel(
    key: String? = null,
    factory: ViewModelProvider.Factory? = null
): Lazy<T> {
    val f = if (AndroidViewModel::class.java.isAssignableFrom(T::class.java)) {
        ViewModelProvider.AndroidViewModelFactory(AppContext.globalContext())
    } else {
        factory
    }
    return lazy(LazyThreadSafetyMode.NONE) {
        (AppContext.globalContext() as ViewModelStoreOwner).viewModel(key, f) as T
    }
}

//fun View.clickWithCheckLogin(listener: View.OnClickListener) {
//    val viewModel =  AppContext.globalContext().viewModel<LoginViewModel>()
//    setOnClickListener {
//        if (viewModel.isLogin()) {
//            listener.onClick(it)
//        } else {
//            it.context.startActivity(Intent(it.context, LoginActivity::class.java))
//        }
//    }
//}


